/*
 * This class can either represent a number of hours worked per day (as an
 * absolute figure) or else a time range.  Either the absolute number or the
 * time range is set for an entire working week; a series of booleans then
 * control which days of the week those figures apply to.  Additionally, another
 * boolean allows the figures to apply to the whol working week; in this
 * scenario, the system will, by default, assume that the hours worked are
 * spread evenly over Monday to Friday.
 *
 * Whether the pattern relates to absolute hours or a time range is controlled
 by the pattern type field.
 *
 */
package TimeRecording.tables;

import TimeRecording.business.DaisyChainSystem;
import TimeRecording.business.DateRange;
import TimeRecording.business.calcs.PatternsSummary;
import TimeRecording.enums.PatternType;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

/**
 *
 * @author cbegg
 */
@Entity
@Table(name = "working_pattern")
@NamedQueries({
    @NamedQuery(
            name = "WorkingPattern.findAll",
            query = "SELECT w " +
                    "FROM WorkingPattern w"),
    @NamedQuery(
            name = "WorkingPattern.findByEmployeeId",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.workingPatternPK.employeeId = :employeeId"),
    @NamedQuery(
            name = "WorkingPattern.findByPatternIndex",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.workingPatternPK.patternIndex = :patternIndex"),
    @NamedQuery(
            name = "WorkingPattern.findByPatternType",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.patternType = :patternType"),
    @NamedQuery(
            name = "WorkingPattern.findByPatternStartDate",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.patternStartDate = :patternStartDate"),
    @NamedQuery(
            name = "WorkingPattern.findByPatternEndDate",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.patternEndDate = :patternEndDate"),
    @NamedQuery(
            name = "WorkingPattern.findByEmployeeAndDateRange",
            query = "SELECT w " +
                    "FROM WorkingPattern w " +
                    "WHERE w.workingPatternPK.employeeId = :employeeId AND " +
                          "w.patternStartDate <= :patternEndDate AND " +
                          "w.patternEndDate >= :patternStartDate")})

public class WorkingPattern implements Serializable {

    private static final long serialVersionUID = 1L;

    // <editor-fold defaultstate="collapsed" desc="Property Change Support">
    @Transient
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Persistent Properties">
    @EmbeddedId
    protected WorkingPatternPK workingPatternPK;

    @Column(name = "type")
    private PatternType patternType;

    @Column(name = "hours")
    private float noOfHours;

    @Basic(optional = false)
    @Column(name = "start_date")
    @Temporal(TemporalType.DATE)
    private Date patternStartDate;

    @Column(name = "end_date")
    @Temporal(TemporalType.DATE)
    private Date patternEndDate;

    @Basic(optional = false)
    @Column(name = "start_time")
    @Temporal(TemporalType.TIME)
    private Date patternStartTime;

    @Column(name = "end_time")
    @Temporal(TemporalType.TIME)
    private Date patternEndTime;

    @Column(name = "monday")
    private Boolean monday;

    @Column(name = "tuesday")
    private Boolean tuesday;

    @Column(name = "wednesday")
    private Boolean wednesday;

    @Column(name = "thursday")
    private Boolean thursday;

    @Column(name = "friday")
    private Boolean friday;

    @Column(name = "saturday")
    private Boolean saturday;

    @Column(name = "sunday")
    private Boolean sunday;

    @JoinColumn(name = "employee_id", referencedColumnName = "employee_id", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Employee employees;
    // </editor-fold>

    public WorkingPattern() {

        patternType = PatternType.DAILY_PAID_TIME;

        patternStartDate = DaisyChainSystem.AGES_AGO;
        patternEndDate = DaisyChainSystem.IN_THE_FUTURE;

        patternStartTime = DaisyChainSystem.DEFAULT_START_TIME;
        patternEndTime = DaisyChainSystem.DEFAULT_FINISH_TIME;
        
        monday = true;
        tuesday = true;
        wednesday = true;
        thursday = true;
        friday = true;
        saturday = false;
        sunday = false;

        noOfHours = 7.5f;
    }

    public WorkingPattern(WorkingPatternPK workingPatternPK) {
        this();
        this.workingPatternPK = workingPatternPK;
    }

    public WorkingPattern(int employeeId, short patternIndex) {
        this();
        this.workingPatternPK = new WorkingPatternPK(employeeId, patternIndex);
    }

    // <editor-fold defaultstate="collapsed" desc="Getters and Setters">

    public WorkingPatternPK getWorkingPatternPK() {
        return workingPatternPK;
    }

    public void setWorkingPatternPK(WorkingPatternPK workingPatternPK) {
        this.workingPatternPK = workingPatternPK;
    }

    public Employee getEmployees() {
        return employees;
    }

    public void setEmployees(Employee employees) {
        Employee oldEmployees = this.employees;
        this.employees = employees;
        changeSupport.firePropertyChange("employees", oldEmployees, employees);
    }

    public Date getPatternStartDate() {
        return patternStartDate;
    }

    public void setPatternStartDate(Date patternStartDate) {
        Date oldPatternStartDate = this.patternStartDate;
        this.patternStartDate = patternStartDate;
        changeSupport.firePropertyChange("patternStartDate", oldPatternStartDate, patternStartDate);
    }

    public Date getPatternEndDate() {
        return patternEndDate;
    }

    public void setPatternEndDate(Date patternEndDate) {
        Date oldPatternEndDate = this.patternEndDate;
        this.patternEndDate = patternEndDate;
        changeSupport.firePropertyChange("patternEndDate", oldPatternEndDate, patternEndDate);
    }
    
    public Date getPatternStartTime() {
        return patternStartTime;
    }

    public void setPatternStartTime(Date patternStartTime) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();

        Date oldPatternStartTime = this.patternStartTime;
        this.patternStartTime = patternStartTime;
        changeSupport.firePropertyChange("patternStartTime", oldPatternStartTime, patternStartTime);

        // This property can only be changed as part of a "clocked" pattern
        // Setting this time will affect the daily and weekly hours

        float dailyHours = getDailyHours();
        changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);

        float weeklyHours = getWeeklyHours();
        changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
    }

    public Date getPatternEndTime() {
        return patternEndTime;
    }

    public void setPatternEndTime(Date patternEndTime) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Date oldPatternEndTime = this.patternEndTime;
        this.patternEndTime = patternEndTime;
        changeSupport.firePropertyChange("patternEndTime", oldPatternEndTime, patternEndTime);

        // This property can only be changed as part of a "clocked" pattern
        // Setting this time will affect the daily and weekly hours

        float dailyHours = getDailyHours();
        changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);

        float weeklyHours = getWeeklyHours();
        changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
    }

    public Boolean getMonday() {
        return ((monday != null && monday) ||
                (patternType == PatternType.FLEXI_PAID_TIME) ||
                (patternType == PatternType.AD_HOC_TIME));
    }

    public void setMonday(Boolean monday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldMonday = this.monday;
        this.monday = monday;
        changeSupport.firePropertyChange("monday", oldMonday, monday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getTuesday() {
        return ((tuesday != null && tuesday) ||
                (patternType == PatternType.FLEXI_PAID_TIME) ||
                (patternType == PatternType.AD_HOC_TIME));
    }

    public void setTuesday(Boolean tuesday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldTuesday = this.tuesday;
        this.tuesday = tuesday;
        changeSupport.firePropertyChange("tuesday", oldTuesday, tuesday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getWednesday() {
        return ((wednesday != null && wednesday) ||
                (patternType == PatternType.FLEXI_PAID_TIME) ||
                (patternType == PatternType.AD_HOC_TIME));
    }

    public void setWednesday(Boolean wednesday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldWednesday = this.wednesday;
        this.wednesday = wednesday;
        changeSupport.firePropertyChange("wednesday", oldWednesday, wednesday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getThursday() {
        return ((thursday != null && thursday) ||
                (patternType == PatternType.FLEXI_PAID_TIME) ||
                (patternType == PatternType.AD_HOC_TIME));
    }

    public void setThursday(Boolean thursday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldThursday = this.thursday;
        this.thursday = thursday;
        changeSupport.firePropertyChange("thursday", oldThursday, thursday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getFriday() {
        return ((friday != null && friday) ||
                (patternType == PatternType.FLEXI_PAID_TIME) ||
                (patternType == PatternType.AD_HOC_TIME));
    }

    public void setFriday(Boolean friday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldFriday = this.friday;
        this.friday = friday;
        changeSupport.firePropertyChange("friday", oldFriday, friday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getSaturday() {
        return (saturday != null && saturday);
    }

    public void setSaturday(Boolean saturday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        
        Boolean oldSaturday = this.saturday;
        this.saturday = saturday;
        changeSupport.firePropertyChange("saturday", oldSaturday, saturday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public Boolean getSunday() {
        return (sunday != null && sunday);
    }

    public void setSunday(Boolean sunday) {

        // Make a note of the old daily and weekly
        // hours as they both might change
        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();

        Boolean oldSunday = this.sunday;
        this.sunday = sunday;
        changeSupport.firePropertyChange("sunday", oldSunday, sunday);

        // Ordinarily, toggling the "day" flag will affect the weekly total
        // except for the weekly-flexi pattern where it divides the weekly total
        // over the number of selected days

        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            float dailyHours = getDailyHours();
            changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);
        } else {
            float weeklyHours = getWeeklyHours();
            changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
        }
    }

    public boolean getDay(int dayOfWeek) {
        switch (dayOfWeek) {
            case GregorianCalendar.MONDAY:
                return getMonday();
            case GregorianCalendar.TUESDAY:
                return getTuesday();
            case GregorianCalendar.WEDNESDAY:
                return getWednesday();
            case GregorianCalendar.THURSDAY:
                return getThursday();
            case GregorianCalendar.FRIDAY:
                return getFriday();
            case GregorianCalendar.SATURDAY:
                return getSaturday();
            case GregorianCalendar.SUNDAY:
                return getSunday();
            default:
                return false;
        }
    }

    /**
     * Get the number of hours for the pattern.  Interpretation of this field
     * depends on the pattern type.  For a clocked pattern, it's flexi or weekly
     * flexi then it represents the number of hours in the week; otherwise it's
     * equal to the number of hours worked on each selected day.
     *
     * @return the number of hours for the pattern.
     */
    public Float getNoOfHours() {
        return noOfHours;
    }

    /**
     * See getNoOfHours javadocs.
     *
     * @param noOfHours
     */
    public void setNoOfHours(float noOfHours) {
        
        // Make a note of the old daily and weekly
        // hours as they both might change

        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();

        Float oldNoOfHours = this.noOfHours;
        this.noOfHours = noOfHours;
        changeSupport.firePropertyChange("noOfHours", oldNoOfHours, noOfHours);

        // Changing this property will also change the weekly and daily hours

        float dailyHours = getDailyHours();
        changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);

        float weeklyHours = getWeeklyHours();
        changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);
    }

    public PatternType getPatternType() {
        return patternType;
    }

    public void setPatternType(PatternType patternType) {

        // Changing the pattern type can screw up
        // just about every fact of the pattern

        float oldDailyHours = getDailyHours();
        float oldWeeklyHours = getWeeklyHours();
        boolean oldMonday = getMonday();
        boolean oldTuesday = getTuesday();
        boolean oldWednesday = getWednesday();
        boolean oldThursday = getThursday();
        boolean oldFriday = getFriday();
        boolean oldSaturday = getSaturday();
        boolean oldSunday = getSunday();

        PatternType oldPeriodType = this.patternType;
        this.patternType = patternType;
        changeSupport.firePropertyChange("patternType", oldPeriodType, patternType);

        // Re-assess "everything" based on the pattern type changing

        float dailyHours = getDailyHours();
        changeSupport.firePropertyChange("dailyHours", oldDailyHours, dailyHours);

        float weeklyHours = getWeeklyHours();
        changeSupport.firePropertyChange("weeklyHours", oldWeeklyHours, weeklyHours);

        boolean newMonday = getMonday();
        changeSupport.firePropertyChange("monday", oldMonday, newMonday);
        
        boolean newTuesday = getTuesday();
        changeSupport.firePropertyChange("tuesday", oldTuesday, newTuesday);
        
        boolean newWednesday = getWednesday();
        changeSupport.firePropertyChange("wednesday", oldWednesday, newWednesday);
        
        boolean newThursday = getThursday();
        changeSupport.firePropertyChange("thursday", oldThursday, newThursday);
        
        boolean newFriday = getFriday();
        changeSupport.firePropertyChange("friday", oldFriday, newFriday);
        
        boolean newSaturday = getSaturday();
        changeSupport.firePropertyChange("saturday", oldSaturday, newSaturday);
        
        boolean newSunday = getSunday();
        changeSupport.firePropertyChange("sunday", oldSunday, newSunday);
    }

    // </editor-fold>

    public int getNoOfWorkingDays() {
        
        return (getMonday() ? 1 : 0) +
                (getTuesday() ? 1 : 0) +
                (getWednesday() ? 1 : 0) +
                (getThursday() ? 1 : 0) +
                (getFriday() ? 1 : 0) +
                (getSaturday() ? 1 : 0) +
                (getSunday() ? 1 : 0);
    }

    public float getDailyHours() {

        // If the pattern type is "paid time" then
        // return our absolute number of hours

        if (patternType == PatternType.DAILY_PAID_TIME ||
                patternType == PatternType.SESSIONAL_TIME) {
            return noOfHours;

        // If the pattern type is "weekly flexi" then return our
        // "number of hours" divided by the number of days worked

        } else if (patternType == PatternType.WEEKLY_PAID_TIME) {

            int days = getNoOfWorkingDays();
            if (days > 0) {
                return noOfHours / days;
            } else {
                return 0;
            }

        // If the pattern type is "flexi time" then assume that the time is
        // allocated over 5 days (figure is shared Monday to Friday)

        } else if (patternType == PatternType.FLEXI_PAID_TIME) {
            return noOfHours / 5;

        // If we're storing a time range then the number of
        // hours is the end time minus the start time

        } else if (patternType == PatternType.CLOCKING_TIME) {
            if (patternStartTime != null && patternEndTime != null) {
                long startMillis = patternStartTime.getTime();
                long endMillis = patternEndTime.getTime();
                long milliseconds = endMillis - startMillis;
                return (float)milliseconds / (60 * 60 * 1000);
            }

        // Someone working ad hoc sessional has no hours
            
        } else if (patternType == PatternType.AD_HOC_TIME) {
            return 0;
        }

        // If there's not enough data (or it's rubbish) then just return zero
        return 0;
    }

    public float getWeeklyHours() {

        // Flexi patterns are stored as a number of hours per week
        if (patternType == PatternType.FLEXI_PAID_TIME) {
            return noOfHours;
        }

        // Weekly-flexi patterns are stored as a number of hours per week
        if (patternType == PatternType.WEEKLY_PAID_TIME) {
            return noOfHours;
        }

        // Ad hoc patterns have no associated hours
        if (patternType == PatternType.AD_HOC_TIME) {
            return 0;
        }

        // For clocked, sessional or fixed daily hours we need to sum the days
        return getNoOfWorkingDays() * getDailyHours();
    }

    public boolean isActive(Date date) {
        return !patternStartDate.after(date) &&
                !patternEndDate.before(date);
    }

    public boolean isWorkingDay(GregorianCalendar cal) {
        if (!isActive(cal.getTime())) {
            return false;
        } else {
            return getDay(cal.get(GregorianCalendar.DAY_OF_WEEK));
        }
    }

    public static List<WorkingPattern> getWorkingPatternsForEmployeeAndDateRange(
            EntityManager entityManager, Employee employee, DateRange dateRange) {

        return entityManager.createNamedQuery("WorkingPattern.findByEmployeeAndDateRange").
                setParameter("employeeId", employee.getEmployeeId()).
                setParameter("patternStartDate", dateRange.getFromDate()).
                setParameter("patternEndDate", dateRange.getToDate()).getResultList();
    }

    public static PatternsSummary calculatePatternsSummary(
            EntityManager entityManager, Employee employee, DateRange range) {

        List<WorkingPattern> patterns = WorkingPattern.
                getWorkingPatternsForEmployeeAndDateRange(
                        entityManager, employee, range);

        GregorianCalendar indexCal = new GregorianCalendar();
        indexCal.setTime(range.getFromDate());

        GregorianCalendar endCal = new GregorianCalendar();
        endCal.setTime(range.getToDate());

        int employedDays = 0;
        int workingDays = 0;
        int potentialWorkingDays = 0;
        double workingHours = 0.0;

        while (!indexCal.after(endCal)) {

            boolean isContracted = false;
            boolean isWorking = false;
            boolean isPotentialWorkingDay = false;

            for (WorkingPattern pattern : patterns) {

                if (pattern.isActive(indexCal.getTime())) {

                    isContracted = true;

                    int day = indexCal.get(GregorianCalendar.DAY_OF_WEEK);
                    if (day != GregorianCalendar.SATURDAY &&
                            day != GregorianCalendar.SUNDAY) {
                        isPotentialWorkingDay = true;
                    }

                    if (pattern.isWorkingDay(indexCal)) {

                        // Ignore zero-hour patterns; ie, a zero-hour flexi
                        // pattern used to accumulate excess hours

                        if (pattern.getDailyHours() > 0) {
                            isWorking = true;
                            workingHours += pattern.getDailyHours();
                        }
                    }
                }
            }

            if (isContracted) {
                employedDays++;
            }

            if (isWorking) {
                workingDays++;
            }

            if (isPotentialWorkingDay) {
                potentialWorkingDays++;
            }

            indexCal.add(GregorianCalendar.DATE, 1);
        }

        return new PatternsSummary(employedDays, workingDays,
                workingHours, potentialWorkingDays);
    }
    // <editor-fold defaultstate="collapsed" desc="Overriden Methods">
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (workingPatternPK != null ? workingPatternPK.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof WorkingPattern)) {
            return false;
        }
        WorkingPattern other = (WorkingPattern) object;
        if ((this.workingPatternPK == null && other.workingPatternPK != null) ||
                (this.workingPatternPK != null && !this.workingPatternPK.equals(other.workingPatternPK))) {
            return false;
        }
        return true;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
            return "TimeRecording.tables.WorkingPattern[]";
    }

    // </editor-fold>
}